﻿using AutoMapper;
using DFGK.WMS.Common.Extensions;
using DFGK.WMS.Common.Result;
using DFGK_WMS.Context;
using DFGK_WMS.IRepository;
using DFGK_WMS.IRepository.IService;
using DFGK_WMS.Model.DTO;
using DFGK_WMS.Model.Enum;
using DFGK_WMS.Model.Models;
using DFGK_WMS.Model.Models.PDA;
using DFGK_WMS.Repository.Service;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;
using NetTaste;
using NPOI.SS.Formula.Functions;
using NPOI.SS.Formula.PTG;
using SqlSugar;
using System.Linq;
using System.Linq.Expressions;
using System.Net.Http;

namespace DFGK_WMS.Repository
{
    public class TransferBinOrderRepository : BaseRepository<TTransferBinOrder>, ITransferBinOrderRepository
    {
        public TransferBinOrderRepository(DFGK_DB context, IMapper mapper) : base(context, mapper)
        {

        }

        /// <summary>
        /// 进行验证
        /// </summary>
        /// <param name="id"></param>
        /// <param name="errMsg"></param>
        /// <returns></returns>
        public bool SubmitTransferCell(int id, out string errMsg)//已弃用做参考
        {
            errMsg = string.Empty;
            //移库单模型

            int instructIndex = 1;
            TTransferBinOrder? transferBinOrder = Context.TTransferBinOrders.FirstOrDefault(it => it.Id == id);
            if (transferBinOrder == null)
            {
                errMsg = "移库单不存在";
                return false;
            }

            if (transferBinOrder.Status != (int)EmBillStatus.Executing)
            {
                errMsg = "移库单状态有误，当前状态：" + ((EmBillStatus)transferBinOrder.Status).GetDescription();
                return false;
            }

            List<TTransferBinOrderDetail> transferDetails = Context.TTransferBinOrderDetails.Where(it => it.OrderId == id).ToList();
            if (transferDetails == null || transferDetails.Count == 0)
            {
                errMsg = "移库单数据有误";
                return false;
            }

            Dictionary<int, TMaterial> materialDic = new Dictionary<int, TMaterial>();
            List<MoveItemModel> moveList = new List<MoveItemModel>();
            foreach (var orderDetail in transferDetails)
            {

                //移库物料
                TMaterial material = null;
                int materialId = orderDetail.MaterialId.GetValueOrDefault();
                if (materialDic.ContainsKey(materialId))
                {
                    material = materialDic[materialId];
                }
                else
                {
                    material = Context.TMaterial.Where(t => t.Id == orderDetail.MaterialId).FirstOrDefault();
                    materialDic[materialId] = material;

                }

                //原始仓位
                TCell fromCell = Context.TCells.Where(it => it.Id == orderDetail.FromLocationId).FirstOrDefault();
                if (fromCell == null)
                {

                    errMsg = "原始仓位不存在";
                    return false;
                }
                if (fromCell.Status != (int)EmCellStatus.Normal || fromCell.FullStatus == 0 || fromCell.IsLock == true)
                {
                    errMsg = "原始仓位状态异常，无法执行任务";
                    return false;
                }

                //库存信息
                TInventory inventory = Context.TInventory.Where(it => it.LocationId == orderDetail.FromLocationId).FirstOrDefault();
                if (inventory == null)
                {
                    errMsg = "库存不存在";
                    return false;
                }

                //目标仓位
                TCell toCell = Context.TCells.Where(it => it.Id == orderDetail.ToLocationId).FirstOrDefault();
                if (toCell == null)
                {
                    errMsg = "目标仓位不存在";
                    return false;
                }
                if (toCell.Status != (int)EmCellStatus.Normal || toCell.FullStatus != 0 || toCell.IsLock == true)
                {
                    errMsg = "目标仓位状态异常，无法执行任务";
                    return false;
                }

                moveList.Add(new MoveItemModel
                {
                    //Type = type,
                    FromCell = fromCell,
                    ToCell = toCell,
                    FromInv = inventory,
                    Material = material,
                    OrderDetail = orderDetail,
                });
            }
            if (moveList == null || moveList.Count == 0)
            {
                errMsg = "数据有误";
                return false;
            }
            #region 排层列相同的起始位与排层列相同目标位 移位原则：最浅对最深，最深对最浅
            //筛选出起始位与目标位都是相同排列层的项
            var lists = moveList.GroupBy(t => FormatLineLayerColumn(t.FromCell) + "~" + FormatLineLayerColumn(t.ToCell))
                .Where(gb => gb.Count() > 1).Select(gb => gb.ToList()).ToList();
            if (lists != null && lists.Count > 0)
            {
                //list 为起始位与目标位是相同排层列的数据
                foreach (var list in lists)
                {
                    var fromDepthIndexs = list.Select(t => t.FromCell.DepthIndex).OrderBy(t => t).ToList();
                    var toDepthIndexs = list.Select(t => t.ToCell.DepthIndex).OrderByDescending(t => t).ToList();
                    for (int n = 0; n <= fromDepthIndexs.Count; n++)
                    {
                        //排层列相同的起始位与排层列相同目标位 移位原则：最浅对最深，最深对最浅
                        var fromDepthIndex = fromDepthIndexs[n];
                        var toDepthIndex = toDepthIndexs[n];
                        var item = list.Find(t => t.FromCell.DepthIndex == fromDepthIndex);
                        if (item.ToCell.DepthIndex != toDepthIndex)
                        {
                            errMsg = "排层列相同的起始位与排层列相同目标位必须遵循最浅对最深、最深对最浅的原则：起始位【" + item.FromCell.Code + "】-->目标位【" + item.ToCell.Code + "】有问题";
                            return false;
                        }
                    }
                }
            }
            #endregion

            #region 检查目标位物料是否与起始位物料品规是一样的
            //如果当前目标位没有最深的，则检查最深的有没有货,没货不需要管，有货要判断物料是否与起始位一致
            var unDepthMoveList = moveList.GroupBy(t => FormatLineLayerColumn(t.ToCell)).ToList();
            if (unDepthMoveList != null && unDepthMoveList.Count > 0)
            {
                foreach (var gb in unDepthMoveList)
                {
                    var moveItem = gb.FirstOrDefault();
                    //int maxDepthIndex = gb.Select(t => t.ToCell.DepthIndex.GetValueOrDefault()).Max();
                    int maxDepthIndex = gb.Max(t => t.ToCell.DepthIndex);
                    for (int depthIndex = maxDepthIndex + 1; depthIndex <= 5; depthIndex++)
                    {
                        string depthCellCode = ReplaceLocationDepth(moveItem.ToCell.Code, depthIndex);
                        TCell depthCell = Context.TCells.Where(t => t.Code == depthCellCode).FirstOrDefault();
                        if (depthCell == null)
                        {
                            break;
                        }
                        //如果在当前任务中,检查是否有库存
                        TInventory depthToInv = Context.TInventory.FirstOrDefault(t => t.Status == (int)EmInventoryStatus.Normal && t.LocationCode == depthCellCode);
                        if (depthToInv != null)
                        {
                            if (moveItem.OrderDetail.IsPriorityFilling == 1)
                            {
                                if (moveItem.OrderDetail.FilterType == 1)
                                {
                                    if (depthToInv.MaterialId != moveItem.FromInv.MaterialId || depthToInv.MaterialKeyId != moveItem.FromInv.MaterialKeyId)
                                    {
                                        errMsg = "当前移位目标位【" + moveItem.ToCell.Code + "】对应的深位存放的物料与起始位【" + moveItem.FromCell.Code + "】物料和批次不一致";
                                        return false;
                                    }
                                }
                                else if (moveItem.OrderDetail.FilterType == 2)
                                {
                                    if (depthToInv.MaterialId != moveItem.FromInv.MaterialId)
                                    {
                                        errMsg = "当前移位目标位【" + moveItem.ToCell.Code + "】对应的深位存放的物料与起始位【" + moveItem.FromCell.Code + "】物料不一致";
                                        return false;
                                    }
                                }
                            }
                        }
                        //if (depthCell.IsMaxDepth == true)
                        //{
                        //    break;
                        //}
                    }
                }
            }
            #endregion

            #region 优先级排序
            //起始位在同一排层列 浅位优先,目标位在同一排层列 深位优先
            List<MoveItemModel> unAllotMoveList = moveList.OrderBy(t => t.FromCell.LineNo)
                .ThenBy(t => t.FromCell.DistanceValue).ThenBy(t => t.FromCell.LayerNo).ThenBy(t => t.FromCell.ColumnNo)
                .ThenBy(t => t.FromCell.DepthIndex).ToList();
            List<MoveItemModel> sortMoveList = new List<MoveItemModel>();
            var fromMoveGroupList = moveList.GroupBy(t => FormatLineLayerColumn(t.FromCell)).Where(gb => gb.Count() > 1).ToList();
            var toMoveGroupList = moveList.GroupBy(t => FormatLineLayerColumn(t.ToCell)).Where(gb => gb.Count() > 1).ToList();
            if (fromMoveGroupList != null && fromMoveGroupList.Count > 0)
            {
                foreach (var fromMoveGb in fromMoveGroupList)
                {
                    var fromMoveList = fromMoveGb.OrderBy(t => t.FromCell.DepthIndex).ToList();
                    foreach (var fromItem in fromMoveList)
                    {
                        if (sortMoveList.Any(t => t.FromCell.Id == fromItem.FromCell.Id && t.ToCell.Id == fromItem.ToCell.Id))
                        {
                            continue;
                        }
                        sortMoveList.Add(fromItem);
                        unAllotMoveList.Remove(fromItem);
                    }
                }
            }
            if (toMoveGroupList != null && toMoveGroupList.Count > 0)
            {
                foreach (var toMoveGb in toMoveGroupList)
                {
                    var toMoveList = toMoveGb.OrderByDescending(t => t.ToCell.DepthIndex).ToList();
                    foreach (var toItem in toMoveList)
                    {
                        if (sortMoveList.Any(t => t.FromCell.Id == toItem.FromCell.Id && t.ToCell.Id == toItem.ToCell.Id))
                        {
                            continue;
                        }
                        sortMoveList.Add(toItem);
                        unAllotMoveList.Remove(toItem);
                    }
                }
            }
            if (unAllotMoveList != null && unAllotMoveList.Count > 0)
            {
                foreach (var unAllotItem in unAllotMoveList)
                {
                    sortMoveList.Add(unAllotItem);
                }
            }
            #endregion

            var inventoryQuery = Context.TInventory;
            var orderQuery = Context.TTransferBinOrders;
            var orderDetailQuery = Context.TTransferBinOrderDetails;
            var cellQuery = Context.TCells;

            List<TPalletMoveRecord> moveRecordList = new List<TPalletMoveRecord>();
            int i = 0;
            List<TInstruct> instructList = new List<TInstruct>();
            List<TInventory> allInventoryList = sortMoveList.Select(t => t.FromInv).ToList();
            foreach (var moveItem in sortMoveList)
            {
                var orderDetail = transferDetails.Find(t => t.FromLocationId == moveItem.FromCell.Id && t.ToLocationId == moveItem.ToCell.Id);
                var fromCell = moveItem.FromCell;
                var toCell = moveItem.ToCell;
                var inventory = moveItem.FromInv;
                TStackingStorage stackingStorage = Context.TStackingStorages.Where(t => t.Status == 1 && t.PalletBarcode == inventory.PalletBarcode).OrderBy(t => t.CreateDate).FirstOrDefault();
                //stackingStorageService.GetStackingStorage(context, new StackingStorageCriteriaModel { Status = 1, PalletBarcode = inventory.PalletBarcode, Order = "DESC", Field = "Id" });
                Guid businessGroupId = Guid.NewGuid();
                #region 要不要临时移位判断
                if (fromCell.DepthIndex > 0) // 在深位
                {
                    int depth = fromCell.DepthIndex != 0 ? fromCell.DepthIndex : 0;
                    for (int lowDepthIndex = 0; lowDepthIndex < depth; lowDepthIndex++)
                    {
                        //如果存在，则不处理,并跳出，必须最挨近的储位才触发生成移位
                        if (allInventoryList.Any(t => t.LocationLineNo == fromCell.LineNo && t.LocationLayerNo == fromCell.LayerNo && t.LocationColumnNo == fromCell.ColumnNo && t.LocationDepth == lowDepthIndex))
                        {
                            continue;
                        }
                        //考虑到（4深位，浅位没有分配，1深位分配，2深位没有分配，3深位分配），去重复
                        if (moveRecordList.Any(t => t.FromCellLineNo == fromCell.LineNo && t.FromCellLayerNo == fromCell.LayerNo && t.FromCellColumnNo == fromCell.ColumnNo && t.FromCellDepthIndex == lowDepthIndex))
                        {
                            continue;
                        }
                        //如果不存在,检查是否是正常库存
                        int lowInvCount = inventoryQuery.Where(t => t.Status == (int)EmInventoryStatus.Normal && t.LocationLineNo == fromCell.LineNo && t.LocationLayerNo == fromCell.LayerNo && t.LocationColumnNo == fromCell.ColumnNo && t.LocationDepth == lowDepthIndex).Count();
                        if (lowInvCount > 0)//如果是正常库存
                        {
                            //再判断是否被其它单据锁定，如果被锁定，则当前单据不能被执行，强制退回
                            List<int?> status = new List<int?>
                  {
                      (int)EmBillStatus.Create,
                      (int)EmBillStatus.Submit,
                      (int)EmBillStatus.Pass,
                  };
                            string lowCellCode = ReplaceLocationDepth(fromCell.Code, lowDepthIndex);
                            int otherOrderLockCount = orderQuery.Join(orderDetailQuery, o => o.Id, od => od.OrderId, (o, od) => new { Order = o, OrderDetail = od })
                                      .Where(x => status.Contains(x.Order.Status) && x.OrderDetail.Id != orderDetail.Id && x.OrderDetail.FromLocationCode == lowCellCode)
                                      .Select(x => x.OrderDetail)
                                      .Count();
                            //如果被锁定，则当前单据不能被执行，强制退回
                            if (otherOrderLockCount > 0)
                            {
                                errMsg = "当前移位单深位【" + fromCell.Code + "】对应的浅位【" + lowCellCode + "】被其它单据锁定";
                                return false;
                            }

                            List<TInventory> moveFromInvs = inventoryQuery.Where(t => t.LocationCode == lowCellCode).ToList();
                            if (moveFromInvs == null || moveFromInvs.Count == 0)
                            {
                                errMsg = "浅位【" + lowCellCode + "】库存不存在，请联系管理员检查数据";
                                return false;
                            }
                            if (moveFromInvs.Any(t => t.Status != (int)EmInventoryStatus.Normal))
                            {
                                errMsg = "浅位【" + lowCellCode + "】库存正在做其它业务，请检查";
                                return false;
                            }

                            TCell moveFromCell = cellQuery.Where(t => t.Code == lowCellCode).FirstOrDefault();
                            if (moveFromCell == null)
                            {
                                errMsg = "浅位【" + lowCellCode + "】货位不存在，请联系管理员检查数据";
                                return false;
                            }
                            string strategyName = "NearestMoveStrategy";
                            if (moveFromInvs.Any(t => t.IsMultPallet == true))
                            {
                                strategyName = "MultPalletNearestMoveStrategy";

                            }
                            TCell allocateCell = GetMoveLockCell(strategyName, moveFromCell, moveFromInvs[0], moveRecordList, out errMsg);

                            if (allocateCell == null)
                            {
                                return false;
                            }
                            //如果没有被其它单锁定，则生成临时移位指令
                            TInstruct moveInstruct = new TInstruct
                            {
                                WarehouseCode = allocateCell.WhCode,
                                Status = 2,
                                FromLocation = moveFromInvs[0].LocationCode,
                                ToLocation = "",
                                ExpectedToLocation = allocateCell.Code,
                                InstructType = (int)EmInstructType.TempMove,
                                WorkDeviceType = (int)EmWorkDeviceType.Line,
                                Action = (int)EmDeviceAction.Transport,
                                InstructIndex = instructIndex,
                                PalletBarcode = moveFromInvs[0].PalletBarcode,
                                Priority = 10000 - instructIndex,
                                ScanedBarcode = moveFromInvs[0].PalletBarcode,
                                StackingStorageId = moveFromInvs[0].StackingStorageId,
                                StartTime = DateTime.Now,
                                Qty = moveFromInvs.Sum(t => t.AvailableQty).Value,
                                FinishedQty = 0,
                                RelatedOrderDetailId = orderDetail.Id,
                                FromRoutewayId = moveFromInvs[0].RoutewayId,
                                BusinessType = (int)EmBusinessType.Move,
                                BusinessGroupId = businessGroupId,
                                //BillType = (int)order.BillType.GetValueOrDefault(),
                                RefCellCode = fromCell.Code,
                                //Cell = moveFromCell
                            };
                            instructIndex++;
                            instructList.Add(moveInstruct);

                            moveRecordList.Add(new TPalletMoveRecord
                            {
                                RelatedOrderDetailId = orderDetail.Id,
                                //BillType = (int)order.BillType.GetValueOrDefault(),
                                BusinessType = (int)EmBusinessType.Move,
                                PalletBarcode = moveFromInvs[0].PalletBarcode,
                                StackingStorageId = moveFromInvs[0].StackingStorageId,
                                InventoryId = moveFromInvs[0].Id,
                                FromCellId = moveFromInvs[0].LocationId.Value,
                                FromCellCode = moveFromInvs[0].LocationCode,
                                FromCellName = moveFromInvs[0].LocationName,
                                FromCellLineNo = moveFromInvs[0].LocationLineNo,
                                FromCellLayerNo = moveFromInvs[0].LocationLayerNo,
                                FromCellColumnNo = moveFromInvs[0].LocationColumnNo,
                                FromCellDepthIndex = moveFromInvs[0].LocationDepth,
                                MoveToCellId = allocateCell.Id,
                                MoveToCellCode = allocateCell.Code,
                                MoveToCellName = allocateCell.Name,
                                MoveToCellLineNo = allocateCell.LineNo,
                                MoveToCellLayerNo = allocateCell.LayerNo,
                                MoveToCellColumnNo = allocateCell.ColumnNo,
                                MoveToCellDepthIndex = allocateCell.DepthIndex,
                                Status = 0,
                                CreateDate = DateTime.Now,
                                FromCellHeightType = moveFromInvs[0].LocationHeightType.Value,
                                MoveToCellHeightType = allocateCell.HeightType,
                                RealHeightType = moveFromInvs[0].RealHeightType,
                                RefCellCode = fromCell.Code,
                                //FromInventory = moveFromInvs[0],
                                IsMultPallet = moveFromInvs[0].IsMultPallet,
                            });
                        }
                    }
                }
                #endregion

                TInstruct instruct = new TInstruct
                {
                    WarehouseCode = inventory.WarehouseCode,
                    Status = 2,
                    FromLocation = fromCell.Code,
                    ToLocation = "",
                    ExpectedToLocation = toCell.Code,
                    //InstructType = this.InstructType,
                    //WorkDeviceType = this.WorkDeviceType,
                    //Action = this.DeviceAction,
                    InstructIndex = instructIndex,
                    PalletBarcode = inventory.PalletBarcode,
                    Priority = 10000 - instructIndex,
                    ScanedBarcode = inventory.PalletBarcode,
                    StackingStorageId = stackingStorage == null ? 0 : stackingStorage.Id,
                    StartTime = DateTime.Now,
                    Qty = inventory.AvailableQty.Value,
                    FinishedQty = 0,
                    RelatedOrderDetailId = orderDetail.Id,
                    FromRoutewayId = fromCell.RoutewayId,
                    BusinessType = (int)EmBusinessType.Move,
                    BusinessGroupId = businessGroupId,
                    //BillType = order.BillType,
                    //Cell = fromCell,
                };
                instructIndex++;
                instructList.Add(instruct);
                i++;
            }
            bool result = false;
            #region 事务处理
            Context.Database.BeginTransaction();

            foreach (TInstruct instruct in instructList)
            {
                TInventory inventory = null;
                TCell toCell = null;
                TPalletMoveRecord moveRecord = null;

                bool isTempMove = instruct.InstructType == (int)EmInstructType.TempMove && instruct.BusinessType == (int)EmBusinessType.Move;
                if (!isTempMove)//如果是正常指令
                {
                    var moveItem = moveList.Find(t => t.FromCell.Code == instruct.FromLocation && t.ToCell.Code == instruct.ExpectedToLocation);
                    inventory = moveItem.FromInv;
                    if (inventory == null)
                    {
                        errMsg = "业务处理异常";
                        Context.Database.RollbackTransaction();
                        return false;
                    }
                    TTransferBinOrderDetail orderDetail = transferDetails.Find(t => t.FromLocationCode == instruct.FromLocation);
                    if (orderDetail == null)
                    {
                        errMsg = "业务处理异常";
                        Context.Database.RollbackTransaction();
                        return false;
                    }
                    toCell = moveItem.ToCell;
                    if (toCell == null)
                    {
                        errMsg = "业务处理异常";
                        Context.Database.RollbackTransaction();
                        return false;
                    }
                }
                else//如果是临时移位
                {
                    moveRecord = moveRecordList.Find(t => t.PalletBarcode == instruct.PalletBarcode);
                    if (moveRecord == null)
                    {
                        errMsg = "未生成移位记录";
                        Context.Database.RollbackTransaction();
                        return false;
                    }
                    inventory = moveRecord.FromInventory;
                }

                Context.TInstructs.Add(instruct);
                int instructId = Context.SaveChanges();
                result = instructId > 0;
                if (!result)
                {
                    errMsg = "指令插入失败";
                    Context.Database.RollbackTransaction();
                    return false;
                }
                //instruct.Id = instructId;

                if (!isTempMove) // 正常移位指令
                {
                    // 库存表
                    var inventoryToUpdate = Context.TInventory.Find(inventory.Id);
                    if (inventoryToUpdate != null)
                    {
                        inventoryToUpdate.IsLock = true;
                        inventoryToUpdate.Status = (int)EmInventoryStatus.InsideWarehouse;
                        inventoryToUpdate.RelatedOrderDetailId = instruct.RelatedOrderDetailId;
                        inventoryToUpdate.BillType = transferBinOrder.BillType;
                    }
                    else
                    {
                        errMsg = "库存状态修改失败";
                        Context.Database.RollbackTransactionAsync();
                        return false;
                    }

                    Context.TInventory.Update(inventoryToUpdate);
                    result = Context.SaveChanges() > 0;

                    if (!result)
                    {
                        errMsg = "库存状态修改失败";
                        Context.Database.RollbackTransactionAsync();
                        return false;
                    }

                    // 锁定起始仓位
                    var cellToUpdate = Context.TCells.Find(inventory.LocationId);
                    if (cellToUpdate != null)
                    {
                        cellToUpdate.IsLock = true;
                        cellToUpdate.BusinessType = (int)EmBusinessType.Move;
                        cellToUpdate.ModifyDate = DateTime.Now;
                        cellToUpdate.Status = (int)EmCellStatus.Lock;
                    }
                    else
                    {
                        errMsg = "保存失败";
                        Context.Database.RollbackTransactionAsync();
                        return false;
                    }

                    Context.TCells.Update(cellToUpdate);
                    result = Context.SaveChanges() > 0;

                    if (!result)
                    {
                        errMsg = "保存失败";
                        Context.Database.RollbackTransactionAsync();
                        return false;
                    }

                    // 锁定目标仓位
                    var toCellToUpdate = Context.TCells.Find(toCell.Id);
                    if (toCellToUpdate != null)
                    {
                        toCellToUpdate.IsLock = true;
                        toCellToUpdate.BusinessType = (int)EmBusinessType.Move;
                        toCellToUpdate.ModifyDate = DateTime.Now;
                        toCellToUpdate.Status = (int)EmCellStatus.Lock;
                    }
                    else
                    {
                        errMsg = "保存失败";
                        Context.Database.RollbackTransactionAsync();
                        return false;
                    }

                    Context.TCells.Update(toCellToUpdate);
                    result = Context.SaveChanges() > 0;

                    if (!result)
                    {
                        errMsg = "保存失败";
                        Context.Database.RollbackTransactionAsync();
                        return false;
                    }
                }
                else
                {
                    //result =  HandleTempMoveBusiness( moveRecord, instructId, out errMsg);
                    if (!result)
                    {
                        Context.Database.RollbackTransactionAsync();
                        return false;
                    }
                }


            }

            Context.Database.CommitTransaction();
            #endregion
            return false;

        }

        /// <summary>
        /// 执行移库
        /// </summary>
        /// <param name="instruct"></param>
        /// <param name="errorMsg"></param>
        /// <returns></returns>
        public bool ExecInstructFinished(int id, out string errMsg)
        {
            // 保存更改以确保 instructs 被添加到数据库

            TInstruct instruct = Context.TInstructs.FirstOrDefault(t => t.Id == id);
            errMsg = "";
            if (instruct is not { ExpectedToLocation: not null, PalletBarcode: not null })
            {
                errMsg = "参数错误";
                return false;
            }
            if (instruct.Status == 3)
            {
                errMsg = "指令已是完成状态，请不要重复调用";
                return false;
            }
            var orderDetailId = instruct.RelatedOrderDetailId.GetValueOrDefault();
            TTransferBinOrderDetail orderDetail = Context.TTransferBinOrderDetails.FirstOrDefault(t => t.Id == orderDetailId);
            if (orderDetail == null)
            {
                errMsg = "参数错误";
                return false;
            }
            TTransferBinOrder order = Context.TTransferBinOrders.FirstOrDefault(t => t.Id == orderDetail.OrderId);
            if (order == null)
            {
                errMsg = "参数错误";
                return false;
            }
            TCell fromcell = Context.TCells.FirstOrDefault(t => t.Id == orderDetail.FromLocationId);
            if (fromcell == null)
            {
                errMsg = "起始仓位有误";
                return false;
            }
            TCell toCell = Context.TCells.FirstOrDefault(t => t.Code == instruct.ExpectedToLocation);
            if (toCell == null)
            {
                errMsg = "目标仓位有误";
                return false;
            }
            TInventory inventory = Context.TInventory.FirstOrDefault(t => t.RelatedOrderDetailId == orderDetail.Id && t.PalletBarcode == instruct.PalletBarcode);
            if (inventory == null)
            {
                errMsg = "未找到库存";
                return false;
            }
            DateTime? now = DateTime.Now;
            bool result = false;

            #region 事务处理
            Context.Database.BeginTransaction();
            var a = Context.TInstructs.FirstOrDefault(m => m.Id == instruct.Id);
            a.Status = 3;
            a.EndTime = now;
            a.FinishedQty = instruct.Qty;
            a.ToLocation = instruct.ExpectedToLocation;
            Context.TInstructs.Update(a);
            result = Context.SaveChanges() > 0;
            if (!result)
            {
                Context.Database.RollbackTransaction();
                return false;
            }
            var b = Context.TInventory.FirstOrDefault(t => t.Id == inventory.Id);
            b.Status = (int)EmInventoryStatus.Normal;
            b.IsLock = false;
            b.LocationId = toCell.Id;
            b.LocationCode = toCell.Code;
            b.LocationDepth = toCell.DepthIndex;
            b.LocationName = toCell.Name;
            b.ErplocationCode = toCell.Erpcode;
            b.RoutewayId = toCell.RoutewayId;
            b.LocationColumnNo = toCell.ColumnNo;
            b.LocationDistanceValue = toCell.DistanceValue;
            b.LocationLayerNo = toCell.LayerNo;
            b.LocationLineNo = toCell.LineNo;
            b.LocationHeightType = toCell.HeightType;
            b.LogicalPartCode = toCell.LogicalPartCode;
            Context.TInventory.Update(b);
            result = Context.SaveChanges() > 0;
            if (!result)
            {
                errMsg = "库存数据更新失败";
                Context.Database.RollbackTransaction();
                return false;
            }
            //起始仓位
            var c = Context.TCells.FirstOrDefault(t => t.Id == fromcell.Id);
            c.IsLock = false;
            c.BusinessType = 0;
            c.Status = (int)EmCellStatus.Normal;
            c.ModifyDate = now;
            c.FullStatus = 0;
            Context.TCells.Update(c);
            result = Context.SaveChanges() > 0;
            if (!result)
            {
                errMsg = "仓位状态修改失败";
                Context.Database.RollbackTransaction();
                return false;
            }
            //目标仓位
            var d = Context.TCells.FirstOrDefault(t => t.Id == toCell.Id);

            d.IsLock = false;
            d.BusinessType = 0;
            d.Status = (int)EmCellStatus.Normal;
            d.ModifyDate = now;
            d.FullStatus = fromcell.FullStatus;
            Context.TCells.Update(c);
            result = Context.SaveChanges() > 0;
            if (!result)
            {
                errMsg = "仓位状态修改失败";
                Context.Database.RollbackTransaction();
                return false;
            }
            if (instruct.StackingStorageId > 0)
            {
                var e = Context.TStackingStorages.FirstOrDefault(t => t.Id == instruct.StackingStorageId);
                e.ExpectedLocation = toCell.Code;
                e.ModifyDate = DateTime.Now;
                Context.TStackingStorages.Update(e);
                result = Context.SaveChanges() > 0;
                if (!result)
                {
                    errMsg = "保存失败";
                    Context.Database.RollbackTransaction();
                    return false;
                }
            };
            TTransferBinOrderDetail modifyOrderDetail = new TTransferBinOrderDetail
            {
                Status = (int)EmBillStatus.Finished,
            };
            var f = Context.TTransferBinOrderDetails.FirstOrDefault(t => t.Id == orderDetail.Id);
            f.Status = (int)EmBillStatus.Finished;
            Context.TTransferBinOrderDetails.Update(f);
            result = Context.SaveChanges() > 0;
            if (!result)
            {
                errMsg = "订单明细修改失败";
                Context.Database.RollbackTransaction();
                return false;
            }
            int unFinishedCount = Context.TTransferBinOrderDetails.Where(t => t.OrderId == order.Id && t.Status != (int)EmBillStatus.Finished).Count();
            if (!result)
            {
                errMsg = "订单完成状态修改失败";
                Context.Database.RollbackTransaction();
                return false;
            }
            #endregion
            return true;

        }

        /// <summary>
        /// 创建移库
        /// </summary>
        /// <param name="req"></param>
        /// <param name="errMs"></param>
        /// <returns></returns>
        public bool CreateTransfer(TTransferBinOrderCreateDTO req, int uid, string uName, out string errMs)
        {
            errMs = string.Empty;

            int instructIndex = 1;
            //原始仓位
            TCell fromCell = Context.TCells.AsNoTracking().Where(it => it.Code == req.LocationCode).FirstOrDefault();
            if (fromCell == null)
            {
                errMs = "原始仓位不存在";
                return false;
            }
            if (fromCell.Status != (int)EmCellStatus.Normal || fromCell.FullStatus == 0 || fromCell.IsLock == true)
            {
                errMs = "原始仓位状态异常，无法执行任务";
                return false;
            }

            //库存信息
            var inventory = Context.TInventory.AsNoTracking().Where(it => it.MaterialId == req.MaterialId && it.LocationId == fromCell.Id).FirstOrDefault();
            if (inventory == null)
            {
                errMs = "库存不存在";
                return false;
            }

            //目标仓位
            TCell toCell = Context.TCells.AsNoTracking().Where(it => it.Code == req.TargetLocationCode).FirstOrDefault();
            if (toCell == null)
            {
                errMs = "目标仓位不存在";
                return false;
            }
            if (toCell.Status != (int)EmCellStatus.Normal || toCell.FullStatus != 0 || toCell.IsLock == true)
            {
                errMs = "目标仓位状态异常，无法执行任务";
                return false;
            }
            TMaterial material = Context.TMaterial.AsNoTracking().Where(it => it.Id == req.MaterialId).FirstOrDefault();

            DateTime currentDateTime = DateTime.Now;
            string year = currentDateTime.ToString("yyyy");
            string month = currentDateTime.ToString("MM");
            string day = currentDateTime.ToString("dd");
            string hour = currentDateTime.ToString("HH");
            string minute = currentDateTime.ToString("mm");
            string second = currentDateTime.ToString("ss");
            string randomNumber = GenerateRandomNumber(1000000, 9999999).ToString();

            string dateTimeRandomNumber = $"{year}{month}{day}{hour}{minute}{second}{randomNumber}";

            List<MoveItemModel> moveList = new List<MoveItemModel>();

            //使用事务的原子性
            using (var trans = Context.Database.BeginTransaction())
            {
                try
                {
                    TTransferBinOrderDetail Detail = Context.TTransferBinOrderDetails.FirstOrDefault(x => x.FromLocationCode == req.LocationCode && x.ToLocationCode == req.TargetLocationCode && x.MaterialId == req.MaterialId && x.Status == 3);

                    TTransferBinOrder tran = new TTransferBinOrder();
                    if (Detail == null)
                    {
                        tran.OrderSn = dateTimeRandomNumber;
                        tran.BillType = 1;
                        tran.CreateUserId = uid;
                        tran.CreateUserName = uName;
                        tran.CreateDate = DateTime.Now;
                        tran.Status = 4;
                        tran.SourceType = 1;
                        tran.CompanyId = 1;
                        tran.CompanyName = uName;
                        tran.Proirity = 0;
                        tran.Erpcode = "";
                        tran.Reason = "";
                        tran.ModifyDate = DateTime.Now;
                        tran.ModifyUserId = uid;
                        tran.ModifyUserName = uName;
                        tran.SubmitDate = DateTime.Now;
                        tran.SubmitUserId = uid;
                        tran.SubmitUserName = uName;
                        tran.AuditUserName = uName;
                        tran.AuditDate = DateTime.Now;
                        tran.AuditUserId = uid;

                        Context.TTransferBinOrders.Add(tran);
                        Context.SaveChanges();
                    }
                    else
                    {
                        tran = Context.TTransferBinOrders.FirstOrDefault(x => x.Id == Detail.OrderId);
                        tran.Status = 4;
                        Context.SaveChanges();
                    }

                    TTransferBinOrderDetail itemDetail = new TTransferBinOrderDetail();
                    if (Detail == null)
                    {
                        itemDetail.Status = 4;
                        itemDetail.OrderId = tran.Id;
                        itemDetail.OrderSn = tran.OrderSn;
                        itemDetail.CreateUserId = tran.CreateUserId;
                        itemDetail.CreateUserName = tran.CreateUserName;
                        itemDetail.CreateDate = tran.CreateDate;
                        itemDetail.ModifyUserId = tran.ModifyUserId;
                        itemDetail.ModifyUserName = tran.ModifyUserName;
                        itemDetail.ModifyDate = tran.ModifyDate;
                        itemDetail.MaterialId = req.MaterialId;
                        itemDetail.MaterialName = material.Name;
                        itemDetail.FromLocationCode = req.LocationCode;
                        itemDetail.FromWhId = inventory.WarehouseId;
                        itemDetail.FromWhCode = inventory.WarehouseCode;
                        itemDetail.FromWhName = inventory.WarehouseName;
                        itemDetail.FromLocationId = inventory.LocationId;
                        itemDetail.FromLocationCode = inventory.LocationCode;
                        itemDetail.FromLocationName = inventory.LocationName;
                        itemDetail.ToWhId = toCell.WhId;
                        itemDetail.ToWhCode = toCell.WhCode;
                        itemDetail.ToWhName = toCell.WhName;
                        itemDetail.ToLocationId = toCell.Id;
                        itemDetail.ToLocationCode = toCell.Code;
                        itemDetail.ToLocationName = toCell.Name;
                        itemDetail.ExpectedStackingQty = 1;
                        itemDetail.ActualStackingQty = 1;
                        itemDetail.Quantity = (int)inventory.AvailableQty;
                        itemDetail.IsFullStackingProirity = true;
                        itemDetail.ToLogicalPartCode = inventory.LogicalPartCode;
                    }
                    else
                    {
                        itemDetail = Detail;
                        tran.Status = 4;
                        Context.SaveChanges();
                    }

                    if (Detail == null)
                    {
                        Context.TTransferBinOrderDetails.Add(itemDetail);
                    }
                   

                    moveList.Add(new MoveItemModel
                    {
                        //Type = type,
                        FromCell = fromCell,
                        ToCell = toCell,
                        FromInv = inventory,
                        Material = material,
                        OrderDetail = itemDetail,
                    });

                    Context.SaveChanges();

                    #region 排层列相同的起始位与排层列相同目标位 移位原则：最浅对最深，最深对最浅
                    //筛选出起始位与目标位都是相同排列层的项
                    var lists = moveList.GroupBy(t => FormatLineLayerColumn(t.FromCell) + "~" + FormatLineLayerColumn(t.ToCell))
                        .Where(gb => gb.Count() > 1).Select(gb => gb.ToList()).ToList();
                    if (lists != null && lists.Count > 0)
                    {
                        //list 为起始位与目标位是相同排层列的数据
                        foreach (var list in lists)
                        {
                            var fromDepthIndexs = list.Select(t => t.FromCell.DepthIndex).OrderBy(t => t).ToList();
                            var toDepthIndexs = list.Select(t => t.ToCell.DepthIndex).OrderByDescending(t => t).ToList();
                            for (int n = 0; n <= fromDepthIndexs.Count; n++)
                            {
                                //排层列相同的起始位与排层列相同目标位 移位原则：最浅对最深，最深对最浅
                                var fromDepthIndex = fromDepthIndexs[n];
                                var toDepthIndex = toDepthIndexs[n];
                                var item = list.Find(t => t.FromCell.DepthIndex == fromDepthIndex);
                                if (item.ToCell.DepthIndex != toDepthIndex)
                                {
                                    errMs = "排层列相同的起始位与排层列相同目标位必须遵循最浅对最深、最深对最浅的原则：起始位【" + item.FromCell.Code + "】-->目标位【" + item.ToCell.Code + "】有问题";
                                    return false;
                                }
                            }
                        }
                    }
                    #endregion

                    #region 检查目标位物料是否与起始位物料品规是一样的
                    //如果当前目标位没有最深的，则检查最深的有没有货,没货不需要管，有货要判断物料是否与起始位一致
                    var unDepthMoveList = moveList.GroupBy(t => FormatLineLayerColumn(t.ToCell)).ToList();
                    if (unDepthMoveList != null && unDepthMoveList.Count > 0)
                    {
                        foreach (var gb in unDepthMoveList)
                        {
                            var moveItem = gb.FirstOrDefault();
                            //int maxDepthIndex = gb.Select(t => t.ToCell.DepthIndex.GetValueOrDefault()).Max();
                            int maxDepthIndex = gb.Max(t => t.ToCell.DepthIndex);
                            for (int depthIndex = maxDepthIndex + 1; depthIndex <= 5; depthIndex++)
                            {
                                string depthCellCode = ReplaceLocationDepth(moveItem.ToCell.Code, depthIndex);
                                TCell depthCell = Context.TCells.Where(t => t.Code == depthCellCode).FirstOrDefault();
                                if (depthCell == null)
                                {
                                    break;
                                }
                                //如果在当前任务中,检查是否有库存
                                TInventory depthToInv = Context.TInventory.FirstOrDefault(t => t.Status == (int)EmInventoryStatus.Normal && t.LocationCode == depthCellCode);
                                if (depthToInv != null)
                                {
                                    if (moveItem.OrderDetail.IsPriorityFilling == 1)
                                    {
                                        if (moveItem.OrderDetail.FilterType == 1)
                                        {
                                            if (depthToInv.MaterialId != moveItem.FromInv.MaterialId || depthToInv.MaterialKeyId != moveItem.FromInv.MaterialKeyId)
                                            {
                                                errMs = "当前移位目标位【" + moveItem.ToCell.Code + "】对应的深位存放的物料与起始位【" + moveItem.FromCell.Code + "】物料和批次不一致";
                                                return false;
                                            }
                                        }
                                        else if (moveItem.OrderDetail.FilterType == 2)
                                        {
                                            if (depthToInv.MaterialId != moveItem.FromInv.MaterialId)
                                            {
                                                errMs = "当前移位目标位【" + moveItem.ToCell.Code + "】对应的深位存放的物料与起始位【" + moveItem.FromCell.Code + "】物料不一致";
                                                return false;
                                            }
                                        }
                                    }
                                }
                                //if (depthCell.IsMaxDepth == true)
                                //{
                                //    break;
                                //}
                            }
                        }
                    }
                    #endregion

                    #region 优先级排序
                    //起始位在同一排层列 浅位优先,目标位在同一排层列 深位优先
                    List<MoveItemModel> unAllotMoveList = moveList.OrderBy(t => t.FromCell.LineNo)
                        .ThenBy(t => t.FromCell.DistanceValue).ThenBy(t => t.FromCell.LayerNo).ThenBy(t => t.FromCell.ColumnNo)
                        .ThenBy(t => t.FromCell.DepthIndex).ToList();
                    List<MoveItemModel> sortMoveList = new List<MoveItemModel>();
                    var fromMoveGroupList = moveList.GroupBy(t => FormatLineLayerColumn(t.FromCell)).Where(gb => gb.Count() > 1).ToList();
                    var toMoveGroupList = moveList.GroupBy(t => FormatLineLayerColumn(t.ToCell)).Where(gb => gb.Count() > 1).ToList();
                    if (fromMoveGroupList != null && fromMoveGroupList.Count > 0)
                    {
                        foreach (var fromMoveGb in fromMoveGroupList)
                        {
                            var fromMoveList = fromMoveGb.OrderBy(t => t.FromCell.DepthIndex).ToList();
                            foreach (var fromItem in fromMoveList)
                            {
                                if (sortMoveList.Any(t => t.FromCell.Id == fromItem.FromCell.Id && t.ToCell.Id == fromItem.ToCell.Id))
                                {
                                    continue;
                                }
                                sortMoveList.Add(fromItem);
                                unAllotMoveList.Remove(fromItem);
                            }
                        }
                    }
                    if (toMoveGroupList != null && toMoveGroupList.Count > 0)
                    {
                        foreach (var toMoveGb in toMoveGroupList)
                        {
                            var toMoveList = toMoveGb.OrderByDescending(t => t.ToCell.DepthIndex).ToList();
                            foreach (var toItem in toMoveList)
                            {
                                if (sortMoveList.Any(t => t.FromCell.Id == toItem.FromCell.Id && t.ToCell.Id == toItem.ToCell.Id))
                                {
                                    continue;
                                }
                                sortMoveList.Add(toItem);
                                unAllotMoveList.Remove(toItem);
                            }
                        }
                    }
                    if (unAllotMoveList != null && unAllotMoveList.Count > 0)
                    {
                        foreach (var unAllotItem in unAllotMoveList)
                        {
                            sortMoveList.Add(unAllotItem);
                        }
                    }
                    #endregion


                    List<TPalletMoveRecord> moveRecordList = new List<TPalletMoveRecord>();
                    int i = 0;
                    List<TInstruct> instructList = new List<TInstruct>();
                    List<TInventory> allInventoryList = sortMoveList.Select(t => t.FromInv).ToList();
                    foreach (var moveItem in sortMoveList)
                    {
                        fromCell = moveItem.FromCell;
                        toCell = moveItem.ToCell;
                        inventory = moveItem.FromInv;
                        TStackingStorage stackingStorage = Context.TStackingStorages.Where(t => t.Status == 1 && t.PalletBarcode == inventory.PalletBarcode).OrderBy(t => t.CreateDate).FirstOrDefault();
                        //stackingStorageService.GetStackingStorage(context, new StackingStorageCriteriaModel { Status = 1, PalletBarcode = inventory.PalletBarcode, Order = "DESC", Field = "Id" });
                        Guid businessGroupId = Guid.NewGuid();
                        #region 要不要临时移位判断
                        if (fromCell.DepthIndex > 0) // 在深位
                        {
                            int depth = fromCell.DepthIndex != 0 ? fromCell.DepthIndex : 0;
                            for (int lowDepthIndex = 0; lowDepthIndex < depth; lowDepthIndex++)
                            {
                                //如果存在，则不处理,并跳出，必须最挨近的储位才触发生成移位
                                if (allInventoryList.Any(t => t.LocationLineNo == fromCell.LineNo && t.LocationLayerNo == fromCell.LayerNo && t.LocationColumnNo == fromCell.ColumnNo && t.LocationDepth == lowDepthIndex))
                                {
                                    continue;
                                }
                                //考虑到（4深位，浅位没有分配，1深位分配，2深位没有分配，3深位分配），去重复
                                if (moveRecordList.Any(t => t.FromCellLineNo == fromCell.LineNo && t.FromCellLayerNo == fromCell.LayerNo && t.FromCellColumnNo == fromCell.ColumnNo && t.FromCellDepthIndex == lowDepthIndex))
                                {
                                    continue;
                                }
                                //如果不存在,检查是否是正常库存
                                int lowInvCount = Context.TInventory.Where(t => t.Status == (int)EmInventoryStatus.Normal && t.LocationLineNo == fromCell.LineNo && t.LocationLayerNo == fromCell.LayerNo && t.LocationColumnNo == fromCell.ColumnNo && t.LocationDepth == lowDepthIndex).Count();
                                if (lowInvCount > 0)//如果是正常库存
                                {
                                    //再判断是否被其它单据锁定，如果被锁定，则当前单据不能被执行，强制退回
                                    List<int?> status = new List<int?>
                  {
                      (int)EmBillStatus.Create,
                      (int)EmBillStatus.Submit,
                      (int)EmBillStatus.Pass,
                  };
                                    string lowCellCode = ReplaceLocationDepth(fromCell.Code, lowDepthIndex);
                                    int otherOrderLockCount = Context.TTransferBinOrders.Join(Context.TTransferBinOrderDetails, o => o.Id, od => od.OrderId, (o, od) => new { Order = o, OrderDetail = od })
                                              .Where(x => status.Contains(x.Order.Status) && x.OrderDetail.Id != itemDetail.Id && x.OrderDetail.FromLocationCode == lowCellCode)
                                              .Select(x => x.OrderDetail)
                                              .Count();
                                    //如果被锁定，则当前单据不能被执行，强制退回
                                    if (otherOrderLockCount > 0)
                                    {
                                        errMs = "当前移位单深位【" + fromCell.Code + "】对应的浅位【" + lowCellCode + "】被其它单据锁定";
                                        return false;
                                    }

                                    List<TInventory> moveFromInvs = Context.TInventory.Where(t => t.LocationCode == lowCellCode).ToList();
                                    if (moveFromInvs == null || moveFromInvs.Count == 0)
                                    {
                                        errMs = "浅位【" + lowCellCode + "】库存不存在，请联系管理员检查数据";
                                        return false;
                                    }
                                    if (moveFromInvs.Any(t => t.Status != (int)EmInventoryStatus.Normal))
                                    {
                                        errMs = "浅位【" + lowCellCode + "】库存正在做其它业务，请检查";
                                        return false;
                                    }

                                    TCell moveFromCell = Context.TCells.Where(t => t.Code == lowCellCode).FirstOrDefault();
                                    if (moveFromCell == null)
                                    {
                                        errMs = "浅位【" + lowCellCode + "】货位不存在，请联系管理员检查数据";
                                        return false;
                                    }
                                    string strategyName = "NearestMoveStrategy";
                                    if (moveFromInvs.Any(t => t.IsMultPallet == true))
                                    {
                                        strategyName = "MultPalletNearestMoveStrategy";

                                    }
                                    TCell allocateCell = GetMoveLockCell(strategyName, moveFromCell, moveFromInvs[0], moveRecordList, out errMs);

                                    if (allocateCell == null)
                                    {
                                        return false;
                                    }
                                    //如果没有被其它单锁定，则生成临时移位指令
                                    TInstruct moveInstruct = new TInstruct
                                    {
                                        WarehouseCode = allocateCell.WhCode,
                                        Status = 2,
                                        FromLocation = moveFromInvs[0].LocationCode,
                                        ToLocation = "",
                                        ExpectedToLocation = allocateCell.Code,
                                        InstructType = (int)EmInstructType.TempMove,
                                        WorkDeviceType = (int)EmWorkDeviceType.Line,
                                        Action = (int)EmDeviceAction.Transport,
                                        InstructIndex = instructIndex,
                                        PalletBarcode = moveFromInvs[0].PalletBarcode,
                                        Priority = 10000 - instructIndex,
                                        ScanedBarcode = moveFromInvs[0].PalletBarcode,
                                        StackingStorageId = moveFromInvs[0].StackingStorageId,
                                        StartTime = DateTime.Now,
                                        Qty = moveFromInvs.Sum(t => t.AvailableQty).Value,
                                        FinishedQty = 0,
                                        RelatedOrderDetailId = itemDetail.Id,
                                        FromRoutewayId = moveFromInvs[0].RoutewayId,
                                        BusinessType = (int)EmBusinessType.Move,
                                        BusinessGroupId = businessGroupId,
                                        //BillType = (int)order.BillType.GetValueOrDefault(),
                                        RefCellCode = fromCell.Code,
                                        //Cell = moveFromCell
                                    };
                                    instructIndex++;
                                    instructList.Add(moveInstruct);
                                    
                                    moveRecordList.Add(new TPalletMoveRecord
                                    {
                                        RelatedOrderDetailId = itemDetail.Id,
                                        //BillType = (int)order.BillType.GetValueOrDefault(),
                                        BusinessType = (int)EmBusinessType.Move,
                                        PalletBarcode = moveFromInvs[0].PalletBarcode,
                                        StackingStorageId = moveFromInvs[0].StackingStorageId,
                                        InventoryId = moveFromInvs[0].Id,
                                        FromCellId = moveFromInvs[0].LocationId.Value,
                                        FromCellCode = moveFromInvs[0].LocationCode,
                                        FromCellName = moveFromInvs[0].LocationName,
                                        FromCellLineNo = moveFromInvs[0].LocationLineNo,
                                        FromCellLayerNo = moveFromInvs[0].LocationLayerNo,
                                        FromCellColumnNo = moveFromInvs[0].LocationColumnNo,
                                        FromCellDepthIndex = moveFromInvs[0].LocationDepth,
                                        MoveToCellId = allocateCell.Id,
                                        MoveToCellCode = allocateCell.Code,
                                        MoveToCellName = allocateCell.Name,
                                        MoveToCellLineNo = allocateCell.LineNo,
                                        MoveToCellLayerNo = allocateCell.LayerNo,
                                        MoveToCellColumnNo = allocateCell.ColumnNo,
                                        MoveToCellDepthIndex = allocateCell.DepthIndex,
                                        Status = 0,
                                        CreateDate = DateTime.Now,
                                        FromCellHeightType = moveFromInvs[0].LocationHeightType.Value,
                                        MoveToCellHeightType = allocateCell.HeightType,
                                        RealHeightType = moveFromInvs[0].RealHeightType,
                                        RefCellCode = fromCell.Code,
                                        //FromInventory = moveFromInvs[0],
                                        IsMultPallet = moveFromInvs[0].IsMultPallet,
                                    });
                                }
                            }
                        }
                        #endregion

                        TInstruct instruct = new TInstruct
                        {
                            WarehouseCode = inventory.WarehouseCode,
                            Status = 2,
                            FromLocation = fromCell.Code,
                            ToLocation = "",
                            ExpectedToLocation = toCell.Code,
                            //InstructType = this.InstructType,
                            //WorkDeviceType = this.WorkDeviceType,
                            //Action = this.DeviceAction,
                            InstructIndex = instructIndex,
                            PalletBarcode = inventory.PalletBarcode,
                            Priority = 10000 - instructIndex,
                            ScanedBarcode = inventory.PalletBarcode,
                            StackingStorageId = stackingStorage == null ? 0 : stackingStorage.Id,
                            StartTime = DateTime.Now,
                            Qty = inventory.AvailableQty.Value,
                            FinishedQty = 0,
                            RelatedOrderDetailId = itemDetail.Id,
                            FromRoutewayId = fromCell.RoutewayId,
                            BusinessType = (int)EmBusinessType.Move,
                            BusinessGroupId = businessGroupId,
                            //BillType = order.BillType,
                            //Cell = fromCell,
                        };
                        instructIndex++;
                        instructList.Add(instruct);
                        i++;
                    }
                    bool result = false;

                    foreach (TInstruct instruct in instructList)
                    {
                        TPalletMoveRecord moveRecord = null;

                        bool isTempMove = instruct.InstructType == (int)EmInstructType.TempMove && instruct.BusinessType == (int)EmBusinessType.Move;
                        if (!isTempMove)//如果是正常指令
                        {
                            var moveItem = moveList.Find(t => t.FromCell.Code == instruct.FromLocation && t.ToCell.Code == instruct.ExpectedToLocation);
                            inventory = moveItem.FromInv;
                            if (inventory == null)
                            {
                                errMs = "业务处理异常";
                                trans.Rollback();
                                return false;
                            }
                            toCell = moveItem.ToCell;
                            if (toCell == null)
                            {
                                errMs = "业务处理异常";
                                trans.Rollback();
                                return false;
                            }
                        }
                        else//如果是临时移位
                        {
                            moveRecord = moveRecordList.Find(t => t.PalletBarcode == instruct.PalletBarcode);
                            if (moveRecord == null)
                            {
                                errMs = "未生成移位记录";
                                trans.Rollback();
                                return false;
                            }
                            inventory = moveRecord.FromInventory;
                        }

                        Context.TInstructs.Add(instruct);
                        int instructId = Context.SaveChanges();
                        result = instructId > 0;
                        if (!result)
                        {
                            errMs = "指令插入失败";
                            trans.Rollback();
                            return false;
                        }
                        if (!isTempMove) // 正常移位指令
                        {
                            var loactionname = Context.TCells.FirstOrDefault(t => t.Code == req.TargetLocationCode).Name;
                          
                            
                            // 库存表 
                            inventory.IsLock = false;
                            inventory.Status = (int)EmInventoryStatus.Normal;
                            inventory.RelatedOrderDetailId = instruct.RelatedOrderDetailId;
                            inventory.BillType = tran.BillType;
                            inventory.LocationCode = req.TargetLocationCode;
                            inventory.LocationName = loactionname;
                            Context.TInventories.Update(inventory);
                            result = Context.SaveChanges() > 0;

                            if (!result)
                            {
                                errMs = "库存状态修改失败";
                                trans.Rollback();
                                return false;
                            }
                            TPallet pall = Context.TPallets.FirstOrDefault(t => t.PalletBarcode == req.PalletBarcode);
                            pall.LocationCode = req.LocationCode;
                            pall.LocationName = loactionname;
                            Context.TPallets.Update(pall);
                            Context.SaveChanges();
                            // 锁定起始仓位 
                            fromCell.IsLock = false;
                            fromCell.BusinessType = (int)EmBusinessType.Move;
                            fromCell.ModifyDate = DateTime.Now;
                            fromCell.Status = (int)EmCellStatus.Normal;

                            Context.TCells.Update(fromCell);
                            result = Context.SaveChanges() > 0;

                            if (!result)
                            {
                                errMs = "保存失败";
                                trans.Rollback();
                                return false;
                            }
                            // 重新获取目标仓位的实体
                            var existingToCell = Context.TCells.Find(toCell.Id);
                            if (existingToCell != null)
                            {
                                // 锁定目标仓位  
                                existingToCell.IsLock = true;
                                existingToCell.BusinessType = (int)EmBusinessType.Move;
                                existingToCell.ModifyDate = DateTime.Now;
                                existingToCell.Status = (int)EmCellStatus.Normal;

                                // 更新目标仓位
                                Context.TCells.Update(existingToCell);  // 将实体标记为已修改
                                result = Context.SaveChanges() > 0;  // 保存更改
                            }
                            else
                            {
                                errMs = "目标仓位不存在";
                                trans.Rollback();
                                return false;
                            }
                            //var loactionname = Context.TCells.FirstOrDefault(t => t.Code == req.TargetLocationCode).Name;


                            //// 库存表 
                            //inventory.IsLock = false;
                            //inventory.Status = (int)EmInventoryStatus.InsideWarehouse;
                            //inventory.RelatedOrderDetailId = instruct.RelatedOrderDetailId;
                            //inventory.BillType = tran.BillType;
                            //inventory.LocationCode = req.TargetLocationCode;
                            //inventory.LocationName = loactionname;
                            //Context.TInventories.Update(inventory);
                            //result = Context.SaveChanges() > 0;

                            ////起始仓位
                            //var c = Context.TCells.FirstOrDefault(t => t.Id == fromCell.Id);
                            //c.IsLock = false;
                            //c.BusinessType = 0;
                            //c.Status = (int)EmCellStatus.Normal;
                            //c.ModifyDate = DateTime.Now;
                            //c.FullStatus = 0;
                            //Context.TCells.Update(c);
                            //result = Context.SaveChanges() > 0;
                            //if (!result)
                            //{
                            //    errMs = "仓位状态修改失败";
                            //    Context.Database.RollbackTransaction();
                            //    return false;
                            //}
                            ////目标仓位
                            //var d = Context.TCells.FirstOrDefault(t => t.Id == toCell.Id);

                            //d.IsLock = false;
                            //d.BusinessType = 0;
                            //d.Status = (int)EmCellStatus.Normal;
                            //d.ModifyDate = DateTime.Now;
                            //d.FullStatus = toCell.FullStatus;
                            //Context.TCells.Update(c);
                            //result = Context.SaveChanges() > 0;

                            if (!result)
                            {
                                errMs = "保存失败";
                                trans.Rollback();
                                return false;
                            }
                        }
                        else
                        {
                            //result =  HandleTempMoveBusiness( moveRecord, instructId, out errMsg);
                            if (!result)
                            {
                                trans.Rollback();
                                return false;
                            }
                        }
                    }

                    //提交事务
                    trans.Commit();
                    return true;
                }
                catch (Exception ex)
                {
                    //事务回滚
                    trans.Rollback();
                    throw;
                }
            }




        }

        private static int GenerateRandomNumber(int min, int max)
        {
            Random random = new Random();
            return random.Next(min, max);
        }

        public TCell GetMoveLockCell(string strategyClassName, TCell fromCell, TInventory fromInv, List<TPalletMoveRecord> moveRecordList, out string errorMsg)
        {
            errorMsg = "";

            TCell cell;
            bool result = AllocateCell(fromCell, fromInv, moveRecordList, out cell, out errorMsg);
            if (!result)
            {
                return null;
            }
            return cell;
        }

        public bool AllocateCell(TCell fromCell, TInventory fromInv, List<TPalletMoveRecord> moveRecordList, out TCell cell, out string errorMsg)
        {
            errorMsg = "";
            cell = null;
            try
            {

                //var fromCell = shippingLockCell.Cell;
                //var fromInv = shippingLockCell.Inventory;
                if (fromCell == null || fromInv == null)
                {
                    errorMsg = "参数错误";
                    return false;
                }
                //DictItemModel commonlogicalPartType = context.Query<DictItemModel>().Where(t => t.TypeCode == ConfigManageHelper.LogicPartCode && t.ItemCode == "MultPallet").FirstOrDefault();

                TCell? allotCell = new TCell();
                var cellQuery = Context.TCells.AsNoTracking().ToList();
                var inventoryQuery = Context.TInventory.AsNoTracking().ToList();
                ////找深位浅位都未空的货位
                //var shelfList=shelfQuery.Where(t => t.Status == 1 && t.WhId == fromCell.WhId && t.AreaId == fromCell.AreaId)
                //    .OrderBy(t => Math.Abs((int)t.Number - (int)fromCell.LineNO)).ToList();
                //if (shelfList == null||shelfList.Count==0)
                //{
                //    errorMsg = "无可用货架";
                //    return false;
                //}
                string logicalPartCode = fromInv.LogicalPartCode;
                int heightType = fromInv.RealHeightType.GetValueOrDefault();

                List<List<TPalletMoveRecord>> moveRecordGroups = null;
                if (moveRecordList != null && moveRecordList.Count > 0)
                {
                    moveRecordGroups = moveRecordList.GroupBy(t => new
                    {
                        t.MoveToCellLineNo,
                        t.BackToCellLayerNo,
                        t.BackToCellColumnNo
                    })
                        .Where(gb => gb.All(t => t.MoveToCellDepthIndex > 0))
                        .OrderBy(gb => Math.Abs(Convert.ToDecimal(Math.Sqrt(Math.Pow(gb.Key.BackToCellLayerNo.GetValueOrDefault(), 2) + Math.Pow(gb.Key.BackToCellColumnNo.GetValueOrDefault(), 2) + Math.Pow(gb.Key.MoveToCellLineNo - 1, 2))) - fromCell.DistanceValue))
                        .Select(gb => gb.ToList()).ToList();
                }

                //优先找该单据临时移位的货位
                if (moveRecordGroups != null && moveRecordGroups.Count > 0)
                {
                    //优先找当前排的
                    List<TPalletMoveRecord> findMoveRecords = moveRecordGroups.Where(t => t[0].MoveToCellHeightType >= fromCell.HeightType
                    && !moveRecordList.Any(r => r.MoveToCellCode == ReplaceLocationDepth(t[0].MoveToCellCode, t.Min(sub => sub.MoveToCellDepthIndex) - 1)))
                        .First();
                    if (findMoveRecords == null)
                    {
                    }
                    else
                    {
                        int minDepthIndex = findMoveRecords.Min(t => t.MoveToCellDepthIndex);
                        string allotCellCode = ReplaceLocationDepth(findMoveRecords[0].MoveToCellCode, minDepthIndex - 1);

                        allotCell = cellQuery.Where(t => t.Code == allotCellCode && t.Status == 1 && t.IsLock == false && t.FullStatus == 0).First();
                    }
                }
                //找一个深浅位全是空的货位且最近的
                if (allotCell == null)
                {

                    List<int> cellIds = moveRecordList.Select(t => t.MoveToCellId).Distinct().ToList();

                    allotCell = cellQuery.Where(t => t.Status == 1 && t.FullStatus == 0 && t.IsLock == false && t.BusinessType == 0 && t.HeightType >= heightType && !cellIds.Contains(t.Id)
                       && !cellQuery.Where(dc => dc.LayerNo == t.LayerNo && dc.LineNo == t.LineNo && dc.ColumnNo == t.ColumnNo
                            && (dc.Status != 1 || dc.IsLock == true || dc.FullStatus != 0 || dc.BusinessType != 0)).Any() && (!string.IsNullOrEmpty(logicalPartCode) ? t.LogicalPartCode == logicalPartCode : true)).FirstOrDefault();

                }
                //找到了，则跳出循环；没找到，则继续下一排货架找
                if (allotCell != null)
                {
                    cell = allotCell;
                }
                if (cell == null && string.IsNullOrEmpty(errorMsg))
                {
                    errorMsg = "没有合适的货位可移位";
                }
                return true;
            }
            catch (Exception ex)
            {
                errorMsg = "未知异常:" + ex.Message;
                return false;
            }
        }


        private string FormatLineLayerColumn(TCell cell)
        {
            return cell.LineNo.ToString() + "_" + cell.LayerNo.ToString() + "_" + cell.ColumnNo.ToString();
        }
        public static string ReplaceLocationDepth(string locationCode, int replaceLocationDepth)
        {
            string[] arr = locationCode.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries);
            if (arr.Length == 5)
            {
                arr[3] = replaceLocationDepth.ToString();
            }
            return string.Join("_", arr);
        }
    }


    public class MoveItemModel
    {
        ///// <summary>
        ///// 1、浅位入深位；2、深位入深位；3、浅位入浅位；4、深位入浅位
        ///// </summary>
        //public int Type
        //{
        //    get; set;
        //}
        public TCell FromCell
        {
            get; set;
        }

        public TInventory FromInv
        {
            get; set;
        }

        public TCell ToCell
        {
            get; set;
        }

        public TMaterial Material
        {
            get; set;
        }

        public TTransferBinOrderDetail OrderDetail
        {
            get; set;
        }

    }
}